package it.poste.il.compensatore.utilities;

import it.poste.il.compensatore.exceptions.CompensatorIOException;
import it.poste.il.compensatore.exceptions.CompensatorTimeOutException;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

public class SendSOAPMessage {

	/**
	 * Log Factory to do the log. 
	 */
	private static LoggerCompensatore loggerF;

	/**
	 * Take the Log Factory to do the log.
	 * @return LogFactory The Entity Log Factory.
	 */
	public LoggerCompensatore getLoggerF() {
		return loggerF;
	}

	/**
	 * Set the Log Factory to do the log.
	 * @param loggerF The Log Factory to set.
	 * @return void
	 */
	public void setLoggerF(LoggerCompensatore loggerF) {
		this.loggerF = loggerF;
	}

	/**
	 * Send the soap request as string and return the response.
	 * @param soapRequest The soap request.
	 * @param destination The url to send request.
	 * @param soapAction The soap action of the request.
	 * @param timeout The timeout for the connection.
	 * @return String The response returned.
	 */
	public String sendStringRequest (String soapRequest, String destination, String soapAction, int timeout) throws CompensatorTimeOutException, CompensatorIOException {
//		LoggerCompensatore logger = (LoggerCompensatore) loggerF.getLogger(this);
		LoggerCompensatore logger=(LoggerCompensatore)loggerF.getLogger(this);
//		LoggerCompensatore logger=(LoggerCompensatore)loggerF.getLogger(this);
		String soapResponse = null;
	  	try {
		  	logger.info("Soap Request: " + soapRequest);
		  	
		  	logger.debug("*** START SEND ***");
			//Setto il timeout
			logger.debug("Timeout: " + timeout);
			HttpParams httpParameters = new BasicHttpParams();
			int timeoutConnection = timeout;
			HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
			int timeoutSocket = timeout;
			HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

			//Setto l'url e il messaggio da inviare
			HttpClient httpClient = new DefaultHttpClient(httpParameters);
			StringEntity entity = new StringEntity(soapRequest,"UTF-8");
			logger.debug("URL: " + destination);
			HttpPost methodPost = new HttpPost(destination);
			methodPost.setEntity(entity);

		    //Setto gli header necessari
			logger.debug("SOAP Action: " + soapAction);
	        methodPost.setHeader("SOAPAction","\""+soapAction+"\"");
	        methodPost.setHeader("Accept-Encoding","gzip, deflate" );
			methodPost.setHeader("Content-Type", "text/xml; charset=UTF-8");  
			
			//Invio il messaggio
			logger.debug("Send SOAP Message ...");
			HttpResponse res=httpClient.execute(methodPost);
			
		    StringBuilder total = new StringBuilder();
			String line = null;
		    HttpEntity resEntity = res.getEntity();
	        if (resEntity != null) {
	        	logger.debug("ResEntity != null");
	        	
	    	    //Necessario per l'encoding
//	            GZIPInputStream gzip=new GZIPInputStream(res.getEntity().getContent());
//	            BufferedReader rd = new BufferedReader(new InputStreamReader(gzip));
	            
	        	InputStream is = resEntity.getContent();
	        	InputStreamReader isr = new InputStreamReader(is);
	        	BufferedReader br = new BufferedReader(isr, 8192);
		        while ( (line = br.readLine()) != null ) {
		        	total.append(line);
		        }
	        }

			soapResponse = total.toString();
			logger.info("The response is: '" + soapResponse + "'");
			logger.info("*** END SEND ***");
	  	} catch (ConnectTimeoutException toe) {
	  		logger.debug("Time out Exception to return.");
	  		//TODO Restituire la CompensatorTimeOutException
	  		throw new CompensatorTimeOutException();
		} catch (IOException e) {
			logger.debug("Errore IOException nel send della richiesta soap: " + e.getMessage());
			logger.debug("The stack trace is: ");
			e.printStackTrace();
			throw new CompensatorIOException();
		}
		return soapResponse;
	}

	/**
	 * Send the soap message of request and return the response.
	 * @param soapMessage The soap message of request.
	 * @param destination The url to send request.
	 * @param soapAction The soap action of the request.
	 * @param timeout The timeout for the connection.
	 * @return String The response returned.
	 */
	public String sendSOAPMessage (SOAPMessage soapMessage, String destination, String soapAction, int timeout) {
		LoggerCompensatore logger = (LoggerCompensatore) loggerF.getLogger(this);
		String soapResponse = null;
	  	try {
	  		ByteArrayOutputStream out = new ByteArrayOutputStream();
			soapMessage.writeTo(out);

		  	String soapRequest = new String(out.toByteArray());
		  	logger.debug("Soap Request: " + soapRequest);
		  	
		  	logger.debug("*** START SEND ***");
			//Setto il timeout
			logger.debug("Timeout: " + timeout);
			HttpParams httpParameters = new BasicHttpParams();
			int timeoutConnection = timeout;
			HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
			int timeoutSocket = timeout;
			HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

			//Setto l'url e il messaggio da inviare
			HttpClient httpClient = new DefaultHttpClient(httpParameters);
			StringEntity entity = new StringEntity(soapRequest,"UTF-8");
			logger.debug("URL: " + destination);
			HttpPost methodPost = new HttpPost(destination);
			methodPost.setEntity(entity);

		    //Setto gli header necessari
			logger.debug("SOAP Action: " + soapAction);
	        methodPost.setHeader("SOAPAction","\""+soapAction+"\"");
	        methodPost.setHeader("Accept-Encoding","gzip, deflate" );
			methodPost.setHeader("Content-Type", "text/xml; charset=UTF-8");  
			
			//Invio il messaggio
			logger.debug("Send SOAP Message ...");
			HttpResponse res=httpClient.execute(methodPost);
			
		    StringBuilder total = new StringBuilder();
			String line = null;
		    HttpEntity resEntity = res.getEntity();
	        if (resEntity != null) {
	        	logger.debug("ResEntity != null");
	        	
	    	    //Necessario per l'encoding
//	            GZIPInputStream gzip=new GZIPInputStream(res.getEntity().getContent());
//	            BufferedReader rd = new BufferedReader(new InputStreamReader(gzip));
	            
	        	InputStream is = resEntity.getContent();
	        	InputStreamReader isr = new InputStreamReader(is);
	        	BufferedReader br = new BufferedReader(isr, 8192);
		        while ( (line = br.readLine()) != null ) {
		        	total.append(line);
		        }
	        }

			soapResponse = total.toString();
			logger.debug("The response is: '" + soapResponse + "'");
			logger.debug("*** END SEND ***");
	  	} catch (ConnectTimeoutException toe) {
	  		logger.debug("Time out Exception to return.");
	  		//TODO Restituire la CompensatorTimeOutException
//	  		throw new CompensatorTimeOutException();
		} catch (SOAPException e) {
			logger.debug("Error SOAPException in send request soap: " + e.getMessage());
			logger.debug("The stack trace is: ");
			e.printStackTrace();
		} catch (IOException e) {
			logger.debug("Error IOException in send request soap: " + e.getMessage());
			logger.debug("The stack trace is: ");
			e.printStackTrace();
		}
		return soapResponse;
	}
	
}